package driver

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"strconv"
	"strings"
	"time"

	"github.com/redis/go-redis/v9"
    
    "collecter/app/common/enum"
    "collecter/app/common/helper"
    "collecter/app/queue/interfaces"
)

/**
*  RedisTaskStruct
*  @Description: 解析后的任务消息体
 */
type RedisTaskStruct struct {
	Key          string // 队列 key
	TaskName     string // 任务名称
	Params       string // 任务参数
	RetryTimes   int64  // 重试次数
	RetryedTimes int64  // 已经重试的次数
	PullKeys     string // 拉取队列消息时传递的队列名称，多个用逗号（英文）隔开
	PullTimeOut  int64  // 从队列拉取消息的超时时间，单位 s
	Delays       int64  // 延时队列的延时时间，单位 s
	State        string // 队列确认时传递的队列任务执行结果。success、failed
}

var redisProvider *redis.Client

func (rts RedisTaskStruct) Connect() error {
	redisProvider = helper.Redis
	return nil
}

func (rts RedisTaskStruct) SetValue(
	key string, taskName string, params string, retryTimes int64, retryedTimes int64, pullKeys string,
	pullTimeOut int64, delays int64, state string) interfaces.DriverIntefacer[MessageStruct] {
	if len(key) > 0 {
		rts.Key = key
	}
	if len(taskName) > 0 {
		rts.TaskName = taskName
	}
	if len(params) > 0 {
		rts.Params = params
	}
	if retryTimes > 0 {
		rts.RetryTimes = retryTimes
	}
	if retryedTimes > 0 {
		rts.RetryedTimes = retryedTimes
	}
	if len(pullKeys) > 0 {
		rts.PullKeys = pullKeys
	}
	if pullTimeOut > 0 {
		rts.PullTimeOut = pullTimeOut
	}
	if delays > 0 {
		rts.Delays = delays
	}
	if len(state) > 0 {
		rts.State = state
	}
	return rts
}

func (rts RedisTaskStruct) Push() error {
	if rts.RetryedTimes <= 0 {
		rts.RetryedTimes = 0
	}
	if rts.RetryTimes <= 0 {
		rts.RetryTimes = helper.Configer.GetInt64("redisQueue.retryTimes")
	}

	var taskStr string

	if taskStrBytes, err := json.Marshal(rts); err != nil {
		errMsg := "推送任务到队列服务提供者出错（序列化任务数据出错），errmsg：" + err.Error() + "，rstValue：" + string(taskStrBytes)
		return errors.New(errMsg)
	} else {
		taskStr = string(taskStrBytes)
	}
	fmt.Printf(" ======== redis-driver Push 消息类型%T, 消息体：%+v\n", taskStr, taskStr)

	ctx := context.Background()
	if err := redisProvider.LPush(ctx, GetKey(rts.Key), taskStr).Err(); err != nil {
		errMsg := "推送任务到队列服务提供者出错（推送任务出错），errmsg：" + err.Error()
		return errors.New(errMsg)
	}
	return nil
}

func (rts RedisTaskStruct) PushDelay(delays int64) error {
	rts.Delays = delays
	return rts.Push()
}

func (rts RedisTaskStruct) Pull() (*MessageStruct, error) {
	var taskInfo *MessageStruct
	queueNames := strings.Split(strings.Trim(rts.PullKeys, " "), ",")
	queueNameLen := len(queueNames)
	for i := 0; i < queueNameLen; i++ {
		queueNames[i] = GetKey(queueNames[i])
	}
	// fmt.Printf("redis driver Pull -> queueNames: %+v\n", queueNames)
	var pullTimeout time.Duration
	if d, err := time.ParseDuration(strconv.Itoa(int(rts.PullTimeOut)) + "s"); err != nil {
		panic("初始化 redis 失败：" + err.Error())
	} else {
		pullTimeout = d
	}
	rst := redisProvider.BRPop(context.Background(), pullTimeout, queueNames...).Val()

	// fmt.Printf(" ===== 从队列拉取到消息,原始消息体：type: %T, %+v\n", rst, rst)
	// fmt.Printf(" ==== rst => %+v, type => %T, len => %d\n", rst[1], rst[1], len(rst[1]))

	if len(rst) > 0 {
		if err := json.Unmarshal([]byte(rst[1]), &taskInfo); err != nil {
			errMsg := "反序列化任务消息出错，errmsg：" + err.Error()
			fmt.Println(errMsg)
			return taskInfo, errors.New(errMsg)
		}
	}
	return taskInfo, nil
}

// 当使用 redis 作为队列服务提供者时，这个接口不予实现，没有意义
func (rts RedisTaskStruct) DeleteTask() error {
	return redisProvider.Del(context.Background(), rts.Key).Err()
}

func (rts RedisTaskStruct) Comfirm() error {
	/*if err := rts.DeleteTask(); err != nil {
		return err
	}*/
	if "success" == rts.State {
		return nil
	}
	rts.RetryedTimes++
	if "failed" == rts.State {
		if rts.RetryTimes == 0 {
			rts.Key = enum.QUEUE_RETRY
		} else {
			if rts.RetryTimes >= rts.RetryedTimes {
				rts.Key = enum.QUEUE_RETRY
			} else {
				rts.Key = enum.QUEUE_DEAD_LETTER
			}
		}

	}
	if "deadLetter" == rts.State {
		rts.Key = enum.QUEUE_DEAD_LETTER
	}
	return rts.Push()
}

func (rts RedisTaskStruct) Info() (map[string]int64, error) {
	queueNames := strings.Split(strings.Trim(rts.PullKeys, " "), ",")
	var forNum = len(queueNames)
	rst := make(map[string]int64)
	for i := 0; i < forNum; i++ {
		ctx := context.Background()
		rst[queueNames[i]] = redisProvider.LLen(ctx, queueNames[i]).Val()
	}

	return rst, nil
}
